package e.odbo.data.model;

import com.openbravo.data.loader.serialize.Datas;
import e.odbo.data.model.comparable.VersionComparable;
import e.odbo.data.model.smaple.PK;

import java.util.*;

public class DataBase {
    String version="1.0.0";

    String name;

    boolean subModel;

    protected List<Table> tables=new ArrayList<>();

    protected List<TableData> initData=new ArrayList<>();

    protected List<TableForeignKey> addForeignKeys=new ArrayList<>();

    protected List<Index>  addIndex=new ArrayList<>();

    protected List<VersionComparable> versionComparables=new ArrayList<>();

    public final static Table versionTable=new Table("odbo_version").implement(PK.PK_String)
                                         .Column("version",ColumnType.VARCHAR(20),ColumnFlag.NotNull);

    public final static Table tableIdGeneratorTable=new Table("odbo_table_id_generator").implement(PK.PK_String)
                                          .Column("next_id_int",ColumnType.INT, ColumnFlag.NotNull)
                                          .Column("next_id_long",ColumnType.LONG, ColumnFlag.NotNull);

    public final static Table lockTable= new Table("odbo_lock").implement(PK.PK_String)
                                          .Column("lock_owner",ColumnType.VARCHAR(50), ColumnFlag.NotNull)
                                          .Column("lock_time",ColumnType.TIMESTAMP);

    public DataBase(String name) {
        this(name,"1.0.0");
    }

    //submodel
    protected Map<String,Column[]> addColumn=new HashMap<>();
    protected Map<String,String[]> removeColumn=new HashMap<>();
    protected Map<String,Column[]> alterColumn=new HashMap<>();

    protected boolean lazyInit=false;

    public DataBase(String name,String version) {
        this(name,version,false);
    }

    public DataBase( String name,String version,boolean subModel) {
        this(name,version,subModel,false);
    }

    public DataBase( String name,String version,boolean subModel,boolean lazyInit) {
        this.version = version;
        this.name = name;
        this.subModel=subModel;
        if(!subModel) {
            addTable(versionTable);
            addTable(tableIdGeneratorTable);
            addTable(lockTable);
        }
        addData(versionTable.getName(),PK.Column_Name,"version").types(Datas.STRING,Datas.STRING).value(name,version);
        addVersionComparable(VersionComparable.VER_3_2_1(version));
        addVersionComparable(VersionComparable.VER_2018_08_01(version));
        this.lazyInit=lazyInit;
    }


    public void lazyInitCheck(){
        if(!lazyInit)
            return;
        initDataBaseStruct();
        lazyInit=false;
    }

    /*
     * 如果表结构很复杂时重载此来使用延迟加载（lazyInit传true），避免不必要的初始化(如只用于版本判断等）。
     */
    protected void initDataBaseStruct(){

    }

    public void addTable(Table ...tables){
        for(Table table:tables)
           this.tables.add(table);
    }

    public void addIndex(Index ...indexs){
        for(Index index:indexs)
            this.addIndex.add(index);
    }

    public void addTableForeignKey(TableForeignKey ...foreignKeys){
        for(TableForeignKey foreignKey:foreignKeys)
            this.addForeignKeys.add(foreignKey);
    }

    public TableData addData(String table, String ...columns){
        TableData tableData=TableData.C(table,columns);
        this.initData.add(tableData);
        return tableData;
    }

    public DataBase addData(TableData tableData){
        this.initData.add(tableData);
        return this;
    }

    public VersionComparable getVersionComparable(){
        for(VersionComparable comparable:this.versionComparables)
            if(comparable.match(version))
                return comparable;
        return null;
    }

    public void addVersionComparable(VersionComparable versionComparable){
        this.versionComparables.add(versionComparable);
    }

    public String getVersion() {
        return version;
    }

    public String getName() {
        return name;
    }

    public List<Table> getTables() {
        lazyInitCheck();
        return tables;
    }

    public List<TableData> getAddData() {
        lazyInitCheck();
        return initData;
    }

    public List<TableForeignKey> getAddForeignKeys() {
        lazyInitCheck();
        return addForeignKeys;
    }

    public List<Index> getAddIndex() {
        lazyInitCheck();
        return addIndex;
    }

    public boolean isSubModel() {
        return subModel;
    }

    public Map<String, Column[]> getAddColumn() {
        lazyInitCheck();
        return addColumn;
    }

    public Map<String, String[]> getRemoveColumn() {
        lazyInitCheck();
        return removeColumn;
    }

    public Map<String, Column[]> getAlterColumn() {
        lazyInitCheck();
        return alterColumn;
    }

    //此为全局，如是模块应在模块内管理
    public  Map<String,Migration> migrations=new HashMap<>();

    public  void registerMigration(Migration migration){
        migrations.put(migration.getSupportVersion(),migration);
    }

    public  Migration[] getMigrationsUP(String fromVersion,String toVersion){
        lazyInitCheck();
        Migration migration=migrations.get(fromVersion);
        if(migration==null)
            return new Migration[]{};
        List<Migration> retMigrations=new ArrayList<>();
        retMigrations.add(migration);
        while(!migration.getCurrentVersion().equalsIgnoreCase(toVersion)){
            migration=migrations.get(migration.getCurrentVersion());
            if(migration==null)
                break;
            retMigrations.add(migration);
        }
        return retMigrations.toArray(new Migration[]{});
    }

    public  Migration[] getMigrationsDown(String fromVersion,String toVersion){
        lazyInitCheck();
        Migration[] migrations= getMigrationsUP(toVersion,fromVersion);
        Migration[] new_array = new Migration[migrations.length];
        for (int i = 0; i < migrations.length; i++) {
            new_array[i] = migrations[migrations.length - i - 1];
        }
        return new_array;

    }

    public Migration migrate(DataBase dataBaseFrom){
        dataBaseFrom.lazyInitCheck();
        lazyInitCheck();
        return null;
    }

    //column
    public DataBase add(String table,Column ...columns){
        if(subModel)
           this.addColumn.put(table,columns);
        return this;
    }

    public DataBase remveColumn(String table,String ...columns){
        if(subModel)
           this.removeColumn.put(table,columns);
        return this;
    }

    public DataBase aliteColumn(String table,Column ...columns){
        if(subModel)
              this.alterColumn.put(table,columns);
        return this;
    }

    public Collection<Migration> getMigrations() {
        lazyInitCheck();
        return this.migrations.values();
    }
}
